package edu.uiowa.ms.hsm;

import java.util.*;

public class LocalSearch {
	private Solution optimum;
	
	public LocalSearch(Solution solution) {
		optimum = solution;
	}
	
	/**
	 * Use best-improvement technique to find this probabilistic neighborhood's local optimum
	 *   (neighborhood defined by Solution.makeSmallChange method).
	 *   
	 * @return	optimum		the local optimum for the neighborhood
	 */
	public Solution probBestImprovement() {
		List <Solution> neighborhood = new ArrayList<Solution>();
		
		for(int i = 0; i < 100; i++){
			Solution candidate = new Solution(
					optimum.numRoutes,
					optimum.maxStopsPerRoute,
					optimum.minStopsPerRoute,
					optimum.demand,
					optimum.time,
					optimum.roadNetwork);
			
			candidate = optimum.clone();
			
			
			candidate.makeSmallChange();
			neighborhood.add(candidate);
			
			//System.out.println("Candidate " +i+ " FITNESS = " + candidate.fitness());
		}
		for (Solution neighbor : neighborhood) {
			if (neighbor.fitness() < optimum.fitness()) {
				optimum = neighbor;
			}
		}
		
		return optimum;
	}
	
	public Solution BestImprovement() {
		List <Solution> neighborhood = new ArrayList<Solution>();
		System.out.println("NEW BEST SEARCH: ");
		
		for(int route = 0; route < optimum.numRoutes; route++){
			Solution candidate = optimum.clone();
			
			int route_length = candidate.end(route) + 1;
			
			//case I.
			if (route_length >= candidate.maxStopsPerRoute){ 
				//System.out.println("MAX_STOPS");
				System.out.println("("+ route + ") del ");
				candidate.delete(route); //delete first node
			//case II.
			}else if (route_length <= candidate.minStopsPerRoute){
				//System.out.println("MIN_STOPS");
				ArrayList <Solution> addList = candidate.add(route);
				if (addList.size() == 0){ //try to add, invert if none possible invert !!!TAKE INTO ACCOUNT FEASBILITY!!!
					System.out.print("("+ route + ") min_invert  ");
					candidate.invert(route);
				}else{
					System.out.print("("+ route + ") min_add" + addList.size() + "  ");
					neighborhood.addAll(addList);
				}
			//case III.
			}else{
				//add all possible:
				System.out.print("("+ route + ") bet ");
				ArrayList <Solution> addList = candidate.add(route);
				if (addList.size() == 0){ //try to add, invert if none possible invert 
					Solution candidate2 = optimum.clone();
					candidate2.invert(route);
					candidate2.generate_RouteNetwork();
					neighborhood.add(candidate2);
					System.out.print(" inv ");
				}else{
					neighborhood.addAll(addList);
					System.out.print(" add_all" + addList.size() + "  ");
				}
				
				//remove first in the route
				System.out.println(" del ");
				candidate.delete(route); 
								
				
			}//End situation III.
			
			candidate.generate_RouteNetwork();
			neighborhood.add(candidate);
		}//end for loop
		
		System.out.println("NUMBER OF POSSIBLE STEPS: " + neighborhood.size());
		for (Solution neighbor : neighborhood) {
			if (neighbor.fitness() < optimum.fitness()) {
				optimum = neighbor;
			}
		}
		
		return optimum;
	}
}
